<template>
    <div class="eval-pane-wrapper">
        <div class="eval-pane-summary">
            <div class="eval-summary-pane">
                <div class="eval-summary-title">评测摘要</div>
                <el-table :data="_metrics" border highlight-current-row style="width: 100%" table-layout="auto"
                    :header-cell-style="headerCellStyle" class="eval-metrics-table">
                    <el-table-column prop="metric" label="metric" min-width="100" />
                    <el-table-column prop="value" label="value" min-width="100" />
                </el-table>
            </div>
            <div class="eval-images-pane">
                <div class="eval-summary-title">评测数据</div>
                <el-table :data="_images" border style="width: 100%" table-layout="fixed"
                    :header-cell-style="headerCellStyle" :cell-style="cellStyle" @row-click="handleRowClick"
                    class="eval-images-table">
                    <el-table-column prop="img_id" label="id" min-width="30" />
                    <el-table-column key="img_name" prop="img_name" label="img_name">
                        <template v-slot="scope">
                            <span class="eval-img-name">{{ scope.row.img_name }}</span>
                        </template>
                    </el-table-column>
                </el-table>
            </div>
        </div>
        <div class="eval-pane-images">
            <div class="eval-images-toolbar">
                <div class="eval-images-header">
                    <div class="eval-images-title">
                        {{ getEvalTitle() }}
                    </div>
                    <div class="eval-images-status">
                        <div class="eval-images-tpfp">
                            <div v-if="_tp.width > 0" :style="{ width: _tp.width + 'px' }" class="eval-images-tp">tp:{{
                                _tp.value }}</div>
                            <div v-if="_fp.width > 0" :style="{ width: _fp.width + 'px' }" class="eval-images-fp">fp:{{
                                _fp.value }}</div>
                            <div v-if="_fn.width > 0" :style="{ width: _fn.width + 'px' }" class="eval-images-fn">fn:{{
                                _fn.value }}</div>
                        </div>
                        <Filter class="eval-filter-icon" @click="_showFilters = !_showFilters"></Filter>
                    </div>
                </div>
                <div v-if="_showFilters" class="eval-filter-wrapper">
                    <div class="eval-filter-title">筛选条件</div>
                    <div class="eval-filter-line">
                        <div class="eval-filter-subtitle">类别</div>
                        <el-select v-model="_filters.categories" multiple size="small" collapse-tags placeholder="类别过滤"
                            class="eval-filter-select">
                            <el-option v-for="category in _categories" :key="category" :label="category"
                                :value="category" />
                        </el-select>
                    </div>
                    <div class="eval-filter-line">
                        <div class="eval-filter-subtitle">iou阈值</div>
                        <el-select v-model="_filters.ious" placeholder="iou过滤" size="small" class="eval-filter-select">
                            <el-option v-for="iou in _ious" :key="iou" :label="iou" :value="iou" />
                        </el-select>
                    </div>
                    <div class="eval-filter-line">
                        <div class="eval-filter-subtitle">尺寸</div>
                        <el-select v-model="_filters.areas" placeholder="尺寸过滤" size="small" class="eval-filter-select">
                            <el-option v-for="area in _areas" :key="area" :label="area" :value="area" />
                        </el-select>
                    </div>
                    <div class="eval-filter-line">
                        <div></div>
                        <el-button type="primary" style="margin-right: 8px" size="small" @click="onClickFilter"> 确 定
                        </el-button>
                    </div>
                </div>
            </div>
            <div class="eval-images-wrapper">
                <div class="eval-images-dt">
                    <div class="image-region-wrapper">
                        <ImageRegion :_region_id="`eval_img_dt`" :_readonly="true" :_toolbar="`none`" :_sync_ops="true"
                            :_show_name="false" :_highlight="false" ref="image_region_dt"
                            @sync-mouse-event="onSyncMouseEventDT"></ImageRegion>
                    </div>
                    <div class="eval-images-dt-status">模型结果</div>
                </div>
                <div class="eval-images-gt">
                    <div class="image-region-wrapper">
                        <ImageRegion :_region_id="`eval_img_gt`" :_readonly="true" :_toolbar="`none`" :_sync_ops="true"
                            :_show_name="false" :_highlight="false" ref="image_region_gt"
                            @sync-mouse-event="onSyncMouseEventGT">
                        </ImageRegion>
                    </div>
                    <div class="eval-images-gt-status">标注真值</div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import { onMounted, ref, getCurrentInstance } from 'vue';
import { getFileBaseName } from '@/js/utils/fileUtils';
import { convertImageEvalResult } from '@/js/utils/evalUtils';
import ImageRegion from '@/components/ToolPages/ImageRegion.vue';
import LabelConfig from '@/js/models/LabelConfig';

const name = 'EvalPanel';
const methods = {
    preLabelData: preLabelData,
    nextLabelData: nextLabelData
};
const { proxy } = getCurrentInstance();
defineExpose({ setEvalResults, handleKeyDown });

let _record_id = ref(null);
let _model_path = ref(null);
let _metrics = ref([]);
let _images = ref([]);
let _current_image = ref(null);
let _current_index = ref(null);

let _tp = ref({
    value: 0,
    width: 0
});
let _fp = ref({
    value: 0,
    width: 0
});
let _fn = ref({
    value: 0,
    width: 0
});

// 过滤条件相关的属性
let _showFilters = ref(false);
let _categories = ref(['ballon']);
let _ious = ref([0.5, 0.6, 0.7, 0.8, 0.9]);
let _areas = ref(['all', 'small', 'medium', 'large']);
let _filters = ref({
    categories: [],
    ious: 0.5,
    areas: 'all'
});

function headerCellStyle({ row, index }) {
    return {
        color: '#222',
        'background-color': '#efefef'
    };
}

function cellStyle({ row, column, rowIndex, columnIndex }) {
    // console.log(row, column, rowIndex, columnIndex);
    let style = {};
    let image = _images.value[_current_index.value];
    if (row.img_id == image.img_id) {
        style['font-weight'] = 'bold';
        if (columnIndex == 0) {
            style['color'] = '#fff';
            style['background-color'] = 'rgb(196, 74, 74)';
        } else {
            style['background-color'] = 'rgb(233, 187, 187)';
        }
    }

    return style;
}

function onClickFilter() {
    _showFilters.value = false;
}

async function handleRowClick(row, column, event) {
    // console.log(`EvalDetails handleRowClick row = `, row);
    _current_image.value = row.img_name;
    let rowIndex = _images.value.findIndex((item) => item.img_id === row.img_id);
    _current_index.value = rowIndex;

    // image_region加载数据
    let { dt, gt } = convertImageEvalResult(row);
    proxy.$refs.image_region_dt.loadData(dt);
    proxy.$refs.image_region_gt.loadData(gt);

    // 更新TP/FP/FN数据
    let { TP, FP, FN } = getTPFPFN(row.eval_details);
    _tp.value.value = TP;
    _fp.value.value = FP;
    _fn.value.value = FN;
    let total_len = 180;
    let total_count = TP + FP + FN;
    _tp.value.width = (total_len * TP) / total_count;
    _fp.value.width = (total_len * FP) / total_count;
    _fn.value.width = (total_len * FN) / total_count;
}

// 从eval_details获取个数
function getTPFPFN(eval_details) {
    // console.log('areas = ', _filters.value.areas);
    // console.log('ious = ', _filters.value.ious);
    let evals = eval_details.filter((item) => {
        return item.area === _filters.value.areas && item.iou_threshold === _filters.value.ious;
    });
    const result = evals.reduce(
        (acc, cur) => {
            acc[cur.annotation_type] = (acc[cur.annotation_type] || 0) + 1;
            return acc;
        },
        { TP: 0, FP: 0, FN: 0 }
    );

    return result;
}

function getEvalTitle() {
    if (_model_path.value) {
        let title = `${getFileBaseName(_model_path.value)}`;
        if (_current_image.value) {
            title += ` | ${_current_image.value}`;
        }
        return title;
    } else {
        return '';
    }
}

function setEvalResults(params) {
    // console.log('setEvalResults eval_results = ', params);
    let { record_id, model_path, eval_details } = params;
    _record_id.value = record_id;
    _model_path.value = model_path;

    // 设置评测结果
    _metrics.value = Object.entries(eval_details.eval_results).map(([key, value]) => ({
        metric: key,
        value: Number(value.toFixed(2))
    }));

    // 设置评测图片信息（将data_samples和eval_details合并到一起）
    let images = [];
    for (let i = 0; i < eval_details.data_samples.length; i++) {
        let image = {};
        image.img_id = eval_details.data_samples[i].img_id;
        image.img_path = eval_details.data_samples[i].img_path;
        image.img_name = eval_details.data_samples[i].img_name;
        image.eval_details = eval_details.eval_details.filter((obj) => obj.image_id === image.img_id);
        images.push(image);
    }
    _images.value = images;
    if (_images.value.length > 0) {
        _current_index.value = 0;
        handleRowClick(_images.value[_current_index.value]);
    } else {
        _current_index.value = null;
    }
}

function onSyncMouseEventDT(args) {
    // console.log('onSyncMouseEventDT args = ', args);
    proxy.$refs.image_region_gt &&
        proxy.$refs.image_region_gt.invokeMethodByName(args.method, {
            sync_tag: true,
            ...args.event
        });
}

function onSyncMouseEventGT(args) {
    // console.log('onSyncMouseEventGT args = ', args);
    proxy.$refs.image_region_dt &&
        proxy.$refs.image_region_dt.invokeMethodByName(args.method, {
            sync_tag: true,
            ...args.event
        });
}

function handleKeyDown(event) {
    // console.log('EvalPanel::handleKeyDown event = ', event);
    LabelConfig.runShortCuts('EvalPanel', methods, event);
}

function preLabelData() {
    // console.log('EvalPanel::preLabelData');
    if (_current_index.value == null) {
        return;
    }
    if (_current_index.value > 0) {
        _current_index.value -= 1;
        handleRowClick(_images.value[_current_index.value]);
    }
}

function nextLabelData() {
    // console.log('EvalPanel::nextLabelData');
    if (_current_index.value == null) {
        return;
    }
    if (_current_index.value >= 0 && _current_index.value < _images.value.length - 1) {
        _current_index.value += 1;
        handleRowClick(_images.value[_current_index.value]);
    }
}

onMounted(async () => { });
</script>

<style scoped>
.eval-pane-wrapper {
    display: flex;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
}

.eval-pane-summary {
    width: 250px;
    height: 100%;
    background-color: rgb(250, 251, 251);
    margin: 2px;
    padding: 3px 3px 10px 3px;
    overflow: hidden;
    box-sizing: border-box;
}

.eval-summary-title {
    font-size: 15px;
    font-weight: 500;
    margin: 10px 3px;
    box-sizing: border-box;
}

.eval-pane-images {
    display: block;
    flex: 1;
    background-color: rgb(217, 218, 214);
    box-sizing: border-box;
}

.eval-images-toolbar {
    position: relative;
    display: flex;
    width: 100%;
    height: 40px;
    background-color: rgb(48, 46, 46);
    box-sizing: border-box;
}

.eval-images-wrapper {
    display: flex;
    padding: 1px;
    width: 100%;
    height: calc(100% - 40px);
    box-sizing: border-box;
    background-color: rgb(87, 87, 88);
}

.eval-summary-pane {
    width: 100%;
    height: 40%;
    overflow: hidden;
    box-sizing: border-box;
}

.eval-images-pane {
    width: 100%;
    height: 60%;
    overflow: hidden;
    box-sizing: border-box;
}

.eval-metrics-table {
    height: calc(100% - 40px);
    overflow: auto;
}

.eval-images-table {
    height: calc(100% - 40px);
    overflow: auto;
}

.eval-img-name {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.eval-images-title {
    font-size: 16px;
    color: rgb(215, 215, 215);
    padding: 11px 0px 0px 15px;
}

.eval-filter-wrapper {
    position: absolute;
    display: block;
    top: 53px;
    right: 3px;
    background-color: rgb(220, 220, 220);
    padding: 8px 10px 3px 10px;
    z-index: 30;
}

.eval-filter-title {
    color: rgb(66, 65, 65);
    font-size: 15px;
    font-weight: 600;
    margin: 0px 3px 5px 0px;
}

.eval-filter-line {
    display: flex;
    justify-content: space-between;
    width: 220px;
    margin: 5px;
    padding: 5px;
}

.eval-filter-subtitle {
    font-size: 14px;
    width: 60px;
    padding-top: 2px;
}

.eval-filter-select {
    width: 150px;
    margin-right: 5px;
}

.eval-images-header {
    width: 100%;
    display: flex;
    justify-content: space-between;
}

.eval-filter-icon {
    padding: 11px;
    width: 18px;
    height: 18px;
    color: white;
}

.eval-filter-icon:hover {
    cursor: pointer;
}

.eval-images-status {
    display: flex;
}

.eval-images-tpfp {
    padding: 11px 5px;
    display: flex;
    align-items: stretch;
}

.eval-images-tp {
    background-color: rgb(13, 159, 110);
    width: 80px;
    height: 18px;
    padding: 0px 3px;
    font-size: 12px;
    color: azure;
    box-sizing: border-box;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border: solid 1px;
    border-color: rgb(124, 126, 126);
}

.eval-images-fp {
    background-color: rgb(241, 48, 119);
    width: 20px;
    height: 18px;
    padding: 0px 3px;
    font-size: 12px;
    color: azure;
    box-sizing: border-box;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border: solid 1px;
    border-color: rgb(124, 126, 126);
}

.eval-images-fn {
    background-color: rgb(225, 103, 9);
    width: 20px;
    height: 18px;
    padding: 0px 3px;
    font-size: 12px;
    color: azure;
    box-sizing: border-box;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border: solid 1px;
    border-color: rgb(124, 126, 126);
}

.eval-images-dt {
    width: 50%;
    height: 100%;
    margin: 1px;
    background-color: black;
}

.eval-images-gt {
    width: 50%;
    height: 100%;
    margin: 1px;
    background-color: black;
}

.image-region-wrapper {
    width: 100%;
    height: calc(100% - 30px);
    box-sizing: border-box;
}

.eval-images-dt-status {
    width: 100%;
    height: 30px;
    background-color: rgb(45, 45, 45);
    color: rgb(190, 190, 190);
    padding: 4px 10px;
    font-size: 12px;
    border: solid 1px;
    border-color: rgb(54, 54, 54);
    box-sizing: border-box;
}

.eval-images-gt-status {
    width: 100%;
    height: 30px;
    background-color: rgb(45, 45, 45);
    color: rgb(190, 190, 190);
    padding: 4px 10px;
    font-size: 12px;
    border: solid 1px;
    border-color: rgb(54, 54, 54);
    box-sizing: border-box;
}
</style>
